
package PV112;

import com.jogamp.opengl.util.gl2.GLUT;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureData;
import com.jogamp.opengl.util.texture.TextureIO;
import java.io.IOException;
import java.net.URL;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.vecmath.Point3f;


public class OpenGlListener implements GLEventListener {
    
    private GLU glu = new GLU();
    //displayList indexes
    private int stozKov = 1, stozBet = 2, stozGum = 3, skyKov = 4, skySklo = 5, ramKov = 6, ramBet = 7, treeIndex = 8, skyIndex = 9, skyboxSklo = 21;
    private float [] freePos = {-5f, 5f, -15f}, cabinPos = {-.5f, 16.2f, -1f}, ropePos = {0f, 16f, -5f}, lookAtFree = {5f, 15f, 5f}, lookAtCabin = {-10f, 15f, -10f}, lookAtRope = {0f, 15f, -5f};
    private float craneRotation = 0f;
    private Texture metalTexture, boxTexture, grassTexture, betonTexture, rubberTexture, glassTexture, skyTexture, treeTexture, rustyTexture, puzzleTexture;
    private Magnet magnet;
    Box box1;
    public static float FLOOR = 0f;
    public static int WIDTH = 24, HEIGHT = 24;
    private List<Box> boxes = new ArrayList<>();
    private boolean [][] positions = new boolean[WIDTH][HEIGHT];
    private CameraType cameraType = CameraType.FREE;
    
    @Override
    public void init(GLAutoDrawable glad) {
        glu = new GLU();
        GL2 gl = glad.getGL().getGL2();
        gl.glShadeModel(GL2.GL_SMOOTH);
        gl.glClearColor(0f, 0f, 0f, 0f);
        gl.glClearDepth(1f);
        gl.glEnable(GL2.GL_DEPTH_TEST);
        gl.glDepthFunc(GL2.GL_LEQUAL);
        gl.glEnable(GL2.GL_TEXTURE_2D);
        gl.glEnable(GL2.GL_BLEND);
        gl.glEnable(GL2.GL_POLYGON_SMOOTH);
        gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
        gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT,GL2.GL_NICEST);
        setupTextures(gl);
        setupLighting(gl);
        loadObject(gl, "fromCinema/stozarKov", stozKov);
        loadObject(gl, "fromCinema/stozarBeton", stozBet);
        loadObject(gl, "fromCinema/stozarGuma", stozGum);
        loadObject(gl, "fromCinema/skyboxKov", skyKov);
        loadObject(gl, "fromCinema/sky", skySklo);
        loadObject(gl, "fromCinema/ramenoKov", ramKov);
        loadObject(gl, "fromCinema/ramenoBeton", ramBet);
        loadObject(gl, "fromCinema/skyboxSklo", skyboxSklo);
        magnet = new Magnet();
        enableCoords(gl);
        magnet.setMain(this);
        magnet.setTurnedOn(false);
        boxes = new ArrayList();
        
        generateBoxes();
        
        Random rnd = new Random();
        int random;
        for (Box b : boxes){
            random = rnd.nextInt(2);
            if (random == 0){
                //boxTexture.bind(gl);
                b.setTexture(boxTexture);
            }else{
                //puzzleTexture.bind(gl);
                b.setTexture(puzzleTexture);
            }
            b.renderCube(gl);
        }
        
        //all false
        for (int i = 0; i < WIDTH; i++){
            for (int j = 0; j < HEIGHT; j++){
                positions[i][j] = false;
            }
        }
        
        //no boxes where is crane located
        for (int i = WIDTH/2 -3; i < WIDTH/2 + 3; i++){
            for (int j = HEIGHT/2 - 3; j < HEIGHT/2 + 3; j++){
                positions[i][j] = true;
            }
        }
        
        gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
    }

    @Override
    public void dispose(GLAutoDrawable glad) {
        
    }

    @Override
    public void display(GLAutoDrawable glad) {
        GL2 gl =  glad.getGL().getGL2();        
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();
        setupCamera(gl, glu);
                
        grassTexture.bind(gl);
        setupFloor(gl);

        metalTexture.bind(gl);        
        gl.glLoadIdentity();
        gl.glScalef(.5f, .5f, .5f);

        float [] mSpecS = { .2f, .2f, .2f, 1.0f };
        float [] mShineS = { 1.2f };
        float [] dif = {.8f, .8f, 1f, 1f};
        
        gl.glLightModelf(GL2.GL_LIGHT_MODEL_COLOR_CONTROL,GL2.GL_SEPARATE_SPECULAR_COLOR); 
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, mSpecS, 0);
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, dif, 0);
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SHININESS, mShineS, 0);
        enableCoords(gl);
        
        gl.glScalef(.1f, .1f, .1f);

        metalTexture.bind(gl);
        gl.glLoadIdentity();
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glCallList(stozKov);
        float [] dif2 = {1f, 1f, 1f, 1f};
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, dif2, 0);
        
        betonTexture.bind(gl);
        gl.glCallList(stozBet);
        rubberTexture.bind(gl);
        gl.glCallList(stozGum);
        
        metalTexture.bind(gl);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glTranslatef(0f, 0f, -1.05f);
        gl.glRotatef(craneRotation, 0f, 1f, 0f);
        gl.glTranslatef(0f, 0f, 1.05f);
        
        gl.glCallList(ramKov); 
        gl.glCallList(skyKov);
        
        //Asi spatne vyexportovane sklo
//        rubberTexture.bind(gl);
//        gl.glCallList(skyboxSklo);
        
        betonTexture.bind(gl);
        gl.glCallList(ramBet);
        
        float [] noSPec = {0f, 0f, 0f, 1f};
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, noSPec, 0);
        float [] noShine = {128f};
        gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SHININESS, noShine, 0);
        
        rubberTexture.bind(gl);
        magnet.setRotation(craneRotation);
        
        magnet.render(gl);
        boxTexture.bind(gl);
        gl.glTranslatef(0f, 0f, .5f);
        gl.glLoadIdentity();
        metalTexture.bind(gl);
        gl.glTranslatef(1.8f, 0f, 0f);
        gl.glRotatef(90f, 0f, 0f, 1f);
        gl.glLoadIdentity();
        gl.glTranslatef(-3f, -2f, 0.5f);
        
        gl.glLoadIdentity();
        gl.glTranslatef(0f, -10f, 0f);
        gl.glScalef(.5f, 1f, .5f);
        skyTexture.bind(gl);
        gl.glCallList(skySklo);
        
        for (Box b : boxes){
            b.renderCube(gl);
        }
        
        drawTrees(gl);
    }
    
        private void enableCoords(GL2 gl){        
        gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_R, GL2.GL_REPEAT);
        gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
        gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
        
    }
    
    private void drawTrees(GL2 gl){
        
        treeIndex = gl.glGenLists(1);
        gl.glNewList(treeIndex, GL2.GL_COMPILE);
        
        treeTexture.bind(gl);
        int rot = 0;
        gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
        gl.glEnable(GL2.GL_ALPHA_TEST);
        gl.glAlphaFunc(GL2.GL_GREATER, .2f);
        for (int i = 0; i < 5; i++){
            gl.glRotatef((float)rot, 0f, 1f, 0f);
            gl.glColor4f(1f, 1f, 1f, .2f);
            gl.glBegin(GL2.GL_QUADS);
                gl.glNormal3f(0f, 0f, 1f);
                float [] v1 = {-.5f, 0f, 0f};
                float [] v2 = {.5f, 0f, 0f};
                float [] v3 = {.5f, 2f, 0f};
                float [] v4 = {-.5f, 2f, 0f};

                gl.glTexCoord2f(1f, 1f);
                gl.glVertex3fv(v1, 0);
                gl.glTexCoord2f(0f, 1f);
                gl.glVertex3fv(v2, 0);
                gl.glTexCoord2f(0f, 0f);
                gl.glVertex3fv(v3, 0);
                gl.glTexCoord2f(1f, 0f);
                gl.glVertex3fv(v4, 0);
            gl.glEnd();
            rot += 18;
        }
        gl.glDepthFunc(GL2.GL_LEQUAL);
        gl.glDisable(GL2.GL_ALPHA_TEST);
        gl.glEndList();
        
        for (int i = -(WIDTH/2 + 4); i < WIDTH/2 + 6; i++){
            gl.glLoadIdentity();
            gl.glTranslatef((float)i, 0f, HEIGHT/2 + 4);
            gl.glCallList(treeIndex);
            gl.glTranslatef(0f, 0f, 1f);
            gl.glCallList(treeIndex);
            gl.glTranslatef(0f, 0f, 1f);
            gl.glCallList(treeIndex);

            gl.glLoadIdentity();
            gl.glTranslatef((float)i, .0f, -(HEIGHT/2 + 5));
            gl.glCallList(treeIndex);
            gl.glTranslatef(0f, 0f, -1f);
            gl.glCallList(treeIndex);
            gl.glTranslatef(0f, 0f, -1f);
            gl.glCallList(treeIndex);
        }
        
        for (int i = -(HEIGHT/2 + 5); i < HEIGHT/2 + 5; i++){
            gl.glLoadIdentity();
            gl.glTranslatef(WIDTH/2 + 5f, 0f, (float)i);
            gl.glCallList(treeIndex);
            gl.glTranslatef(1f, 0f, 0f);
            gl.glCallList(treeIndex);
            gl.glTranslatef(1f, 0f, 0f);

            gl.glCallList(treeIndex);

            gl.glLoadIdentity();
            gl.glTranslatef(-(HEIGHT/2 + 3f), 0f,(float)i);
            gl.glCallList(treeIndex);
            gl.glTranslatef(1f, 0f, 0f);
            gl.glCallList(treeIndex);
            gl.glTranslatef(1f, 0f, 0f);
            gl.glCallList(treeIndex);
        }
    }

    @Override
    public void reshape(GLAutoDrawable glad, int i, int i1, int i2, int i3) {
        GL2 gl = glad.getGL().getGL2();
        gl.glViewport(i, i1, i2, i3);
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45, 16/9, 0.1, 100);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
    
    public void zoom (double amnt, GL2 gl){
        switch (cameraType){
            case FREE:
                freePos[2] += amnt;
                break;
                //není dle zadání
//            case CABIN:
//                cabinPos[2] += amnt;
//                break;
//            case ROPE:
//                ropePos[2] += amnt;
//                break;
        };
    }
    
    private void lookCamera(GL2 gl){
        if (cameraType == CameraType.FREE){
            glu.gluLookAt(freePos[0], freePos[1], freePos[2], lookAtFree[0], lookAtFree[1], lookAtFree[2], 0f, 1f, 0f);
        }else if (cameraType == CameraType.CABIN){
            glu.gluLookAt(cabinPos[0], cabinPos[1], cabinPos[2], lookAtCabin[0], lookAtCabin[1], lookAtCabin[2], 0f, 1f, 0f);
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glTranslatef(0f, 0f, -1.05f);

        gl.glRotatef(-craneRotation, 0f, 1f, 0f);
        gl.glTranslatef(0f, 0f, 1.05f);
        }else{
        gl.glMatrixMode(GL2.GL_PROJECTION);
        glu.gluLookAt(ropePos[0], ropePos[1], ropePos[2], lookAtRope[0], lookAtRope[1], lookAtRope[2], 0f, 0f, 1f);
        gl.glTranslatef(0f, 0f, -1.05f);
        gl.glRotatef(-craneRotation, 0f, 1f, 0f);
        gl.glTranslatef(0f, 0f, 1.05f);
        }
    }
    
        private void setupCamera(GL2 gl, GLU glu){
    gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45, 16/9, .1, 1000);
        lookCamera(gl);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
    private void setupFloor(GL2 gl){
        enableCoords(gl);
        gl.glLoadIdentity();
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        
        int index = 99;
        index = gl.glGenLists(1);
        gl.glNewList(index, GL2.GL_COMPILE);
        
        gl.glBegin(GL2.GL_QUADS);
            gl.glNormal3f(0f, 1f, 0f);
            gl.glTexCoord2f(0f, 0f);
            gl.glVertex3f(-.5f, 0f, -.5f);
            gl.glTexCoord2f(1f, 0f);
            gl.glVertex3f(.5f, 0f, -.5f);
            gl.glTexCoord2f(1f, 1f);
            gl.glVertex3f(.5f, 0f, .5f);
            gl.glTexCoord2f(0f, 1f);
            gl.glVertex3f(-.5f, 0f, .5f);
        gl.glEnd();
        
        gl.glEndList();
        
        gl.glLoadIdentity();
        
        for (int i = -(WIDTH/2 + 5); i < (WIDTH/2 + 5); i++){
            gl.glLoadIdentity();
            gl.glTranslatef(-(WIDTH/2 + 5), 0f, (float)i);
            for (int j = -(HEIGHT/2 + 5); j < (HEIGHT/2 + 5); j++){
                gl.glTranslatef(1f, 0f, 0f);
                gl.glCallList(index);
            }
        }
        
    }
    
        private void loadObject(GL2 gl, String name, int index){
        ObjLoader loader = new ObjLoader("/resources/" + name + ".obj");
        loader.load();
        
        index = gl.glGenLists(1);
        gl.glNewList(index, GL2.GL_COMPILE);
        
        gl.glBegin(GL2.GL_TRIANGLES);
        List<int[]> vertInd = loader.getVertexIndices();
        List<float[]> vert = loader.getVertices();
        loader.getVertexIndices();

        for (int i = 0; i < vertInd.size(); i++){
            int  [] indices = loader.getVertexIndices().get(i);
            float [] v1 = loader.getVertices().get(indices[0]);
            float [] v2 = loader.getVertices().get(indices[1]);
            float [] v3 = loader.getVertices().get(indices[2]);
        
            int  [] normals = loader.getNormalIndices().get(i);
            
            float [] n1 = loader.getNormals().get(normals[0]);
            float [] n2 = loader.getNormals().get(normals[1]);
            float [] n3 = loader.getNormals().get(normals[2]);
            
            int [] textures = loader.getTextureIndices().get(i);
            float [] t1 = loader.getTextures().get(textures[0]);
            float [] t2 = loader.getTextures().get(textures[1]);
            float [] t3 = loader.getTextures().get(textures[2]);
            
            gl.glNormal3fv(n1, 0);
            gl.glTexCoord2fv(t1, 0);
            gl.glVertex3fv(v1, 0);
            
            gl.glNormal3fv(n2, 0);
            gl.glTexCoord2fv(t2, 0);
            gl.glVertex3fv(v2, 0);
            
            gl.glNormal3fv(n3, 0);
            gl.glTexCoord2fv(t3, 0);
            gl.glVertex3fv(v3, 0);
        }
        
        gl.glEnd();
        
        gl.glEndList();
    }

    public void rotateCrane(float amnt, GL2 gl){
        craneRotation += amnt;
        magnet.setRotation(craneRotation);
        moveBox(magnet.getColisionPosition());
    }
    
    public void moveRail(float amnt, GL2 gl){
        if (((magnet.getPosition().z - Magnet.MIN_DISTANCE) > 0.2f) & (Magnet.MAX_DISTANCE - magnet.getPosition().z > 0.2f)){
            magnet.setPosition(new Point3f(magnet.getPosition().x, magnet.getPosition().y, magnet.getPosition().z + amnt));
        }else if ((amnt > 0) & magnet.getPosition().z <= (Magnet.MIN_DISTANCE + amnt)){
            magnet.setPosition(new Point3f(magnet.getPosition().x, magnet.getPosition().y, magnet.getPosition().z + amnt));
        }else if ((amnt < 0) & magnet.getPosition().z >= (Magnet.MAX_DISTANCE + amnt)){
            magnet.setPosition(new Point3f(magnet.getPosition().x, magnet.getPosition().y, magnet.getPosition().z + amnt));
        }
        moveBox(magnet.getColisionPosition());
//        magnet.writeInfo();
    }
    
    public void moveMagnet(float amnt, GL2 gl){
        if (magnet.getPosition().y > Magnet.MIN_HIGH & magnet.getPosition().y < Magnet.MAX_HIGH){
            magnet.setPosition(new Point3f(magnet.getPosition().x, magnet.getPosition().y + amnt, magnet.getPosition().z));
        }else if ((amnt > 0) & magnet.getPosition().y <= (Magnet.MIN_HIGH + amnt)){
            magnet.setPosition(new Point3f(magnet.getPosition().x, magnet.getPosition().y + amnt, magnet.getPosition().z));
        }else if ((amnt < 0) & magnet.getPosition().y >= (Magnet.MAX_HIGH + amnt)){
            magnet.setPosition(new Point3f(magnet.getPosition().x, magnet.getPosition().y + amnt, magnet.getPosition().z));
        }
        moveBox(magnet.getColisionPosition());
//        magnet.writeInfo();
    }
    
    public void moveBox(Point3f magnetPosition){
        if (magnet.isTurnedOn()){
            Box movedBox = null;
            float distance = Float.MAX_EXPONENT;
            for (Box b : boxes){
                float x = Math.abs(b.getCenter().x - magnetPosition.x);
                float y = Math.abs(b.getCenter().y - magnetPosition.y);
                float z = Math.abs(b.getCenter().z - magnetPosition.z);
//                System.out.println("Box " +  b.getIndex() + " at: " + b.getPosition().x + ", " + b.getPosition().y + ", " + b.getPosition().z);
                if (x < magnet.getRadius()*1.5 & y < magnet.getRadius()*1.5 & z < magnet.getRadius()*1.5){
                    float dst = x*x + y*y + z*z;
                    if (dst < distance){
                        distance = dst;
                        movedBox = b;
//                        System.out.println("Close enough : "+dst);
                    }
                }else{
//                    System.out.println("Not close" + x + ", " + y + ", " + z);
                }
//                System.out.println("Magnet at: " + magnet.getColisionPosition().x +", " + magnet.getColisionPosition().y + ", "  + magnet.getColisionPosition().z);
//                System.out.println("======================================");
            }
            if (movedBox != null){
                magnet.setActiveBox(movedBox);
                movedBox.setCenter(new Point3f(magnet.getColisionPosition().x, magnet.getColisionPosition().y - 1.25f, magnet.getColisionPosition().z));
            }
        }
    }

    void toggleMagnet() {
        magnet.setTurnedOn(!magnet.isTurnedOn());
    }
    
    private void generateBoxes(){
        Random rndX = new Random();
        Random rndY = new Random();
        for (int i = 0; i < 30; i++){
            int xP = rndX.nextInt (WIDTH);
            int yP = rndY.nextInt(HEIGHT);
            if (positions[xP][yP] != true){
                Box b = new Box(i, new Point3f((float)xP - WIDTH/2, .5f, (float)yP - WIDTH/2));
                boxes.add(b);
            } else {
            }
        }
    }

    public void setCameraType(CameraType cameraType) {
        this.cameraType = cameraType;
    }

    public CameraType getCameraType() {
        return cameraType;
    }
    
    public void moveVerically(float amnt, GL2 gl){
//        lookAt[1] += amnt;
        //craneLookVer += amnt;
        switch (cameraType){
            case FREE:
                lookAtFree[1] += amnt;
                break;
            case CABIN:
                lookAtCabin[1] += amnt;
                break;
            case ROPE:
                lookAtRope[2] += amnt / 3;
        }
    }
    public void moveHorizontally(float amnt, GL2 gl){
        switch (cameraType){
            case FREE:
                lookAtFree[0] -= amnt;
                break;
            case CABIN:
                lookAtCabin[0] += amnt;
                break;
            case ROPE:
                lookAtRope[0] -= amnt / 3;
                break;
        }
    }

        private void setupTextures(GL2 gl){
        URL urlMetal = getClass().getResource("/resources/misc8.jpg");
        URL urlGrass = getClass().getResource("/resources/grass.jpg");
        URL urlBox = getClass().getResource("/resources/box.png");
        URL urlBeton = getClass().getResource("/resources/beton.jpg");
        URL urlRubber = getClass().getResource("/resources/rubber.jpg");
        URL urlSky = getClass().getResource("/resources/sky.jpg");
        URL urlTree = getClass().getResource("/resources/tree.png");
        URL urlRusty = getClass().getResource("/resources/rusty.jpg");
        URL urlGlass = getClass().getResource("/resources/glass.jpg");
        URL urlPuzzle = getClass().getResource("/resources/puzzle.jpg");
        TextureData dataMetal, dataGrass, dataBox, dataBeton, dataRubber, dataSky, dataTree, dataRusty, dataGlass, dataPuzzle;
        try {
            dataMetal = TextureIO.newTextureData(gl.getGLProfile(), urlMetal, true, TextureIO.JPG);
            metalTexture = new Texture(gl, dataMetal);
            dataGrass = TextureIO.newTextureData(gl.getGLProfile(), urlGrass, true, TextureIO.JPG);
            grassTexture = new Texture(gl, dataGrass);
            dataBox = TextureIO.newTextureData(gl.getGLProfile(), urlBox, true, TextureIO.PNG);
            boxTexture = new Texture(gl, dataBox);
            dataBeton = TextureIO.newTextureData(gl.getGLProfile(), urlBeton, true, TextureIO.JPG);
            betonTexture = new Texture(gl, dataBeton);
            dataRubber = TextureIO.newTextureData(gl.getGLProfile(), urlRubber, true, TextureIO.JPG);
            rubberTexture = new Texture(gl, dataRubber);
            dataSky = TextureIO.newTextureData(gl.getGLProfile(), urlSky, true, TextureIO.JPG);
            skyTexture = new Texture(gl, dataSky);
            dataTree = TextureIO.newTextureData(gl.getGLProfile(), urlTree, true, TextureIO.PNG);
            treeTexture = new Texture(gl, dataTree);
            dataRusty = TextureIO.newTextureData(gl.getGLProfile(), urlRusty, true, TextureIO.JPG);
            rustyTexture = new Texture(gl, dataRusty);
            dataGlass = TextureIO.newTextureData(gl.getGLProfile(), urlGlass, true, TextureIO.JPG);
            glassTexture = new Texture(gl, dataGlass);
            dataPuzzle = TextureIO.newTextureData(gl.getGLProfile(), urlPuzzle, true, TextureIO.JPG);
            puzzleTexture = new Texture(gl, dataPuzzle);
        } catch (IOException ex) {
            Logger.getLogger(OpenGlListener.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Texture not generated properly.");
        }
    }
            
    private void setupLighting(GL2 gl){
        gl.glEnable(GL2.GL_LIGHTING);
        gl.glEnable(GL2.GL_LIGHT0);
        gl.glEnable(GL2.GL_LIGHT1);
        gl.glEnable(GL2.GL_LIGHT2);
        gl.glEnable(GL2.GL_LIGHT3);
        gl.glEnable(GL2.GL_LIGHT4);
        
//        spotlight pro magnet
        gl.glEnable(GL2.GL_LIGHT5);
        
        float [] spot1 = {1f, 0f, 1f};
        float [] spot2 = {1f, 0f, -1f};
        float [] spot3 = {-1f, 0f, 1f};
        float [] spot4 = {-1f, 0f, -1f};
        float [] spot5 = {0f, -1f, 0f};
        
        float [] ambi0 = {.8f, .8f, .8f, 1f};
        float [] ambi1 = {.4f, .4f, 0f, 1f};
        float [] ambi2 = {.4f, 0f, .4f, 1f};
        float [] ambi3 = {0f, .4f, .4f, 1f};
        float [] ambi4 = {.4f, 0f, .4f, 1f};
        float [] ambi5 = {.4f, .3f, .3f, 1f};
        float [] pos0 = {-5f, 15f, -5f, 1f};
        float [] spec = {.3f, .3f, .3f, 1f};
        float [] pos1 = {-(float)WIDTH, 10f, -(float)HEIGHT, 1f};
        float [] pos2 = {-(float)WIDTH, 10f, (float)HEIGHT, 1f};
        float [] pos3 = {(float)WIDTH, 10f, -(float)HEIGHT, 1f};
        float [] pos4 = {(float)WIDTH, 10f, (float)HEIGHT, 1f};
        float [] pos5 = {0f, 16f, -5f, 1f};
        float [] difu0 = {.2f, .2f, .2f, 1f};
        float [] difu1 = {1f, .8f, 1f, 1f};
        float [] difu2 = {1f, 1f, .8f, 1f};
        float [] difu3 = {.8f, 1f, .8f, 1f};
        float [] difu4 = {.8f, .8f, 1f, 1f};
        float [] difu5 = {1f, .8f, 1f, 1f};
        float [] cutoff = {30f};
        float att = (float) 1/512;
        float expo = 4f;
        
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos0, 0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, ambi0, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, ambi1, 0);
        gl.glLightfv(GL2.GL_LIGHT2, GL2.GL_AMBIENT, ambi2, 0);
        gl.glLightfv(GL2.GL_LIGHT3, GL2.GL_AMBIENT, ambi3, 0);
        gl.glLightfv(GL2.GL_LIGHT4, GL2.GL_AMBIENT, ambi4, 0);
        gl.glLightfv(GL2.GL_LIGHT5, GL2.GL_AMBIENT, ambi4, 0);
        gl.glLightfv(GL2.GL_LIGHT5, GL2.GL_AMBIENT, ambi5, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, pos1, 0);
        gl.glLightfv(GL2.GL_LIGHT2, GL2.GL_POSITION, pos2, 0);
        gl.glLightfv(GL2.GL_LIGHT3, GL2.GL_POSITION, pos3, 0);
        gl.glLightfv(GL2.GL_LIGHT4, GL2.GL_POSITION, pos4, 0);
        gl.glLightfv(GL2.GL_LIGHT5, GL2.GL_POSITION, pos5, 0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, spec, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, spec, 0);
        gl.glLightfv(GL2.GL_LIGHT2, GL2.GL_SPECULAR, spec, 0);
        gl.glLightfv(GL2.GL_LIGHT3, GL2.GL_SPECULAR, spec, 0);
        gl.glLightfv(GL2.GL_LIGHT4, GL2.GL_SPECULAR, spec, 0);
        gl.glLightfv(GL2.GL_LIGHT5, GL2.GL_SPECULAR, spec, 0);
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, difu0, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, difu1, 0);
        gl.glLightfv(GL2.GL_LIGHT2, GL2.GL_DIFFUSE, difu2, 0);
        gl.glLightfv(GL2.GL_LIGHT3, GL2.GL_DIFFUSE, difu3, 0);
        gl.glLightfv(GL2.GL_LIGHT4, GL2.GL_DIFFUSE, difu4, 0);
        gl.glLightfv(GL2.GL_LIGHT5, GL2.GL_DIFFUSE, difu5, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPOT_DIRECTION, spot1, 0);
        gl.glLightfv(GL2.GL_LIGHT2, GL2.GL_SPOT_DIRECTION, spot2, 0);
        gl.glLightfv(GL2.GL_LIGHT3, GL2.GL_SPOT_DIRECTION, spot3, 0);
        gl.glLightfv(GL2.GL_LIGHT4, GL2.GL_SPOT_DIRECTION, spot4, 0);
        gl.glLightfv(GL2.GL_LIGHT5, GL2.GL_SPOT_DIRECTION, spot5, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPOT_CUTOFF, cutoff, 0);
        gl.glLightfv(GL2.GL_LIGHT2, GL2.GL_SPOT_CUTOFF, cutoff, 0);
        gl.glLightfv(GL2.GL_LIGHT3, GL2.GL_SPOT_CUTOFF, cutoff, 0);
        gl.glLightfv(GL2.GL_LIGHT4, GL2.GL_SPOT_CUTOFF, cutoff, 0);
        gl.glLightf(GL2.GL_LIGHT1, GL2.GL_QUADRATIC_ATTENUATION, att);
        gl.glLightf(GL2.GL_LIGHT1, GL2.GL_SPOT_EXPONENT, expo);
        gl.glLightf(GL2.GL_LIGHT2, GL2.GL_QUADRATIC_ATTENUATION, att);
        gl.glLightf(GL2.GL_LIGHT2, GL2.GL_SPOT_EXPONENT, expo);
        gl.glLightf(GL2.GL_LIGHT3, GL2.GL_QUADRATIC_ATTENUATION, att);
        gl.glLightf(GL2.GL_LIGHT3, GL2.GL_SPOT_EXPONENT, expo);
        gl.glLightf(GL2.GL_LIGHT4, GL2.GL_QUADRATIC_ATTENUATION, att);
        gl.glLightf(GL2.GL_LIGHT4, GL2.GL_SPOT_EXPONENT, expo);    
        gl.glLightf(GL2.GL_LIGHT5, GL2.GL_SPOT_EXPONENT, expo);    
    }

    public Texture getRubberTexture() {
        return rubberTexture;
    }

    public Texture getToxicTexture() {
        return rustyTexture;
    }
    
}
